/* eslint-disable */
import { createRouter, createWebHistory }  from 'vue-router'

// 引入各页面组件
import Layout from "@/components/web/layout";

// 状态管理器
import store from "@/store";
import { getToken } from "@/utils/auth";

// 页面加载进度
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
NProgress.configure({ showSpinner: false });

// 路由路径白名单 - 可不用登录直接放行
const whiteList = ['/site-index', '/develop-trend']

// 侧边栏组件
import layout from "@/components/web/layout";

/**
 * Note: 路由配置项
 *
 * hidden: true                     // 当设置 true 的时候该路由不会再侧边栏出现 如401，login等页面，或者如一些编辑页面/edit/1 (可以理解为全屏页面)
 * alwaysShow: true                 // 当你一个路由下面的 children 声明的路由大于1个时，自动会变成嵌套的模式--如组件页面
 *                                  // 只有一个时，会将那个子路由当做根路由显示在侧边栏--如引导页面
 *                                  // 若你想 不管路由下面的 children 声明的个数为几个 都嵌套显示 可以设置 alwaysShow: true
 *                                  // 你可以设置 alwaysShow: true，这样它就会忽略之前定义的规则，一直显示根路由
 * redirect: noRedirect             // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
 * name:'router-name'               // 设定路由的名字，一定要填写不然使用<keep-alive>时会出现各种问题 首字母大写 eg:Index Main
 * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
 * roles: ['admin', 'common']       // 访问路由的角色权限
 * permissions: ['a:a:a', 'b:b:b']  // 访问路由的菜单权限
 * meta : {
    noCache: true                   // 如果设置为true，则不会被 <keep-alive> 缓存(默认 false)
    title: 'title'                  // 设置该路由在侧边栏和面包屑中展示的名字
    icon: 'svg-name'                // 设置该路由的图标，对应路径src/assets/icons/svg
    breadcrumb: false               // 如果设置为false，则不会在breadcrumb面包屑中显示
    activeMenu: '/system/user'      // 当路由设置了该属性，则会高亮相对应的侧边栏。
  }
 */


/**
 * 静态路由 以及 不需要显示在菜单栏的动态路由
 * 备注：component值很关键（组件路径） 用于去找到本地对应组件 默认都在根目录views文件夹下面
 * @type {[{path: string, component: (function(): Promise<{}>), hidden: boolean, name: string},{path: string, component: {}, children: [{path: string, component: (function(): Promise<{readonly default?: {components: {}, data(): {tableData: []}, created(), methods: {uploadDataReq(): void}, name: string, setup(), beforeCreate(), mounted(): void, props: {}}}>), meta: {activeMenu: string, icon: string, title: string}, name: string, index: string}], meta: {activeMenu: string, icon: string, title: string}, name: string, index: string}]}
 */
 export const staticRoutes = [
     // 处理重定向的路由
    {
        path: "/redirect",
        component: Layout,
        hidden: true,
        children: [
            {
                path: "/redirect/:path(.*)",
                component: () => import("@/views/redirect"),
            },
        ],
    },
    // 登录(是全屏的 不用赋值给菜单数据)
    {
        path:'/login',
        name:'login',
        hidden:true,
        component: () => import('../views/login'),
        // component: () => import('../components/AppLogin'),
    },
    {
        path: "/404",
        component: () => import("@/views/error/404"),
        hidden: true,
    },
    {
        path: "/401",
        component: () => import("@/views/error/401"),
        hidden: true,
    },
    {
        path: "/site-index",
        name:'官网',
        component: () => import("@/views/site/index"),
        hidden: true,
    },
    {
        path: "/develop-trend",
        name:'发展趋势',
        component: () => import("@/views/site/develop-trend"),
        hidden: true,
    },

    // 首页 - 为什么单页面也要放一个children 因为外层的父级需要以Layout作为组件 这样就有了框架 父菜单路由路径和子路由路径一样 这样就直接访问了子路由
    // {
    //     path:'/index',
    //     name:'Index',
    //     meta:{
    //         icon:'HomeFilled',
    //         title:'首页',
    //         activeMenu:'0-0',
    //         affix: true,
    //     },
    //     component: Layout,
    //     index:'0-0',
    //     alwaysShow:false,
    //     children:[
    //         {
    //             path:'/index',
    //             name:'Main',
    //             component:() => import('@/views/main'),
    //             meta:{
    //                 icon:'HomeFilled',
    //                 title:'首页',
    //                 activeMenu:'0-0',
    //                 affix: true,
    //             },
    //             index:'0-0',
    //         }
    //     ]
    // },
    // 作为push进入的界面 - 某个菜单子页面其下的详情页面或者要push进入的页面 栈的概念       component:layout说明它不是全屏页面 需要layout框架
    // {
    //     path:'/main/userInfo',
    //     hidden:true,
    //     component:layout,
    //     children:[
    //         {
    //             // 可以传参
    //             path:'',
    //             name:'UserInfo',
    //             component:() => import('@/views/main/userInfo'),
    //             meta:{
    //                 icon:'Menu',
    //                 title:'个人信息',
    //                 activeMenu:'0-0',
    //             },
    //         }
    //     ]
    // },
    // {
    //     path:'/main/userInfoSetting',
    //     hidden:true,
    //     component:layout,
    //     children:[
    //         {
    //             // 可以传参
    //             path:'',
    //             name:'UserInfoSetting',
    //             component:() => import('@/views/main/userInfoSetting'),
    //             meta:{
    //                 icon:'Menu',
    //                 title:'个人信息设置',
    //                 activeMenu:'0-0',
    //             },
    //         }
    //     ]
    // },
    {
        path:'/workdemo/detail',
        hidden:true,
        component:layout,
        children:[
            {
                path:'',
                name:'WorkdemoDetail',
                component:() => import('@/views/dashboard/workdemo-detail'),
                meta:{
                    icon:'Menu',
                    title:'详情页',
                    activeMenu:'2-1',
                }
            }
        ]
    }
]


// 路由管理者
export const router = createRouter({
    // 使用hash 路由路径会多一个# 使用当前这种方式 会和路由路径设置的一样
    history: createWebHistory(),
    base: process.env.BASE_URL,
    // 所有的静态路由
    routes: staticRoutes,
})

/**
 * 获取路由对象
 * @param item
 * @returns {{path: string, component: {}, children: [{path: string, component: function(): Promise<*>, meta: {}, name: string}], meta: {icon: string, id: string}, name: string}}
 */
const getRoute = item => {
    // 路由基本格式
    let route = {
        // 路由的路径
        path: item.path,
        // 路由名
        name: item.name,
        // 重定向
        redirect: item.redirect,
        alwaysShow:item.alwaysShow,
        // 额外数据
        meta: item.meta,
        // index标记 对应菜单界面索引
        index: item.index,
    }

    // 路由组件地址
    if (item.component == 'layout') {
        // layout
        route.component = Layout
    } else {
        // 非layout
        route.component = loadView(item.component)
    }
    if (item && item.children.length > 0) {
        route.children = getChildrenRoutes(item.children, item)
    }
    return route
}

/**
 * 根据组件本地路径 导入为路由需要的组件对象（默认在views文件夹下）
 * @param view
 * @returns {function(): Promise<*>}
 */
export const loadView = (view) => {
    // if (process.env.NODE_ENV === 'development') {
    //     return (resolve) => require([`@/views/${view}`], resolve)
    // } else {
    //     // 使用 import 实现生产环境的路由懒加载
    //     return () => import(`@/views/${view}`)
    // }
    // 使用 import 实现生产环境的路由懒加载
    return () => import(`@/views/${view}`)
}


/**
 * 获取某个菜单下的所有子菜单路由数据
 * @param children
 * @returns {[]}
 */
const getChildrenRoutes = (allRoutes, subRoute) => {
    let arr = []
    allRoutes.forEach(item => {
        const route = getRoute(item)
        // 将父菜单的名称写入子菜单的元数据里面
        route.meta.subname = subRoute && subRoute.meta && subRoute.meta.title ? subRoute.meta.title : ''
        arr.push(route)
    })
    if (arr.length == 1) {
        let route = arr[0]
        if (!subRoute.alwaysShow) {
            // 特殊处理：当菜单下只有一个子菜单 且不嵌套显示 作为根路由展示时 子菜单路由路径取值为父菜单路由路径
            // 当子菜单只有一个且父级要求其作为根路由展示时 path赋值和父菜单一样的路径 这样直接作为根路径展示
            route.path = subRoute.path
        }
    }
    return arr
}

/**
 * 路由守卫: 可以在此做路由跳转前的校验 只有执行了next()函数 才会去执行下一个钩子函数
 */
router.beforeEach((to, from, next) => {
    NProgress.start()

    console.log('上一个路由', from)
    console.log('目标路由', to)
    console.log('路由数据：', router.getRoutes())

    const title = to.meta && to.meta.title ? to.meta.title : ''
    store.dispatch('UpdateDocumentTitle', title).then(r => {})

    // 更改上一次点击的菜单索引 - 便于下一次页面刷新继续保持在上一次停留页面并点亮该页面对应菜单
    if (to.meta && to.meta.activeMenu) {
        store.commit('SET_ACTIVE_MENU', to.meta.activeMenu)
    }

    // 根据有无存储token来判断是否登录
    const isLogin = getToken('token')
    if (isLogin) {
        console.log('已登录')
        if (to.path === '/login' || to.path === '/' || to.path === '/index2') {
            // 登录过就不能访问登录界面，需要中断这一次路由守卫，执行下一次路由守卫，并且下一次守卫的to是主页
            // 如果输入/index错误 但是包含了/index 可以跳转到/indexs
            next({ path:'/index' })
            NProgress.done()
            return
        }
        if (store.getters.dynamicRoutes.length == 0) {
            console.log('动态路由为空')
            // 判断当前用户是否已拉取完user_info信息
            store.dispatch('GetUserInfo').then(() => {
                store.dispatch('GenerateRoutes').then(accessRoutes => {
                    // 根据roles权限生成可访问的路由表 - 动态路由部分
                    let dynamicRoutes = []
                    accessRoutes.forEach(menu => {
                        // 动态添加可访问路由表 - 父菜单
                        const subRoute = getRoute(menu)
                        console.log('subRoute', subRoute)
                        if (!router.hasRoute(subRoute.name)) {
                            router.addRoute(subRoute);
                            dynamicRoutes.push(subRoute);
                        }

                        // 菜单下的子菜单
                        const children = menu.children
                        if (children.length > 1 || menu.alwaysShow) {
                            // 子菜单有多个 或者 一个时不作根路由显示
                            children.forEach(child => {
                                // 子菜单的路径： 父菜单路径 + / + 子菜单路径 所以有多级目录时子菜单路径填写无需添加/
                                if (child.path && child.path.length > 0 && child.path != '/index') {
                                    child.path = menu.path  + '/' + child.path
                                }
                                const childRoute = getRoute(child)
                                if (!router.hasRoute(childRoute.name)) {
                                    router.addRoute(subRoute.name, childRoute)
                                    dynamicRoutes.push(childRoute)
                                }
                            })
                        }
                    })

                    // 含有通配符的路由应该放在最后(非常特殊的路由)
                    // 识别不到的path 自动调转404
                    // vue2使用* vue3使用:pathMatch('*') 或者 :pathMatch('*')* 或者 :catchAll(.*)
                    const notFindRoute = { path: '/:catchAll(.*)', redirect: '/404', hidden: true }
                    router.addRoute(notFindRoute)

                    // 根据roles权限生成可访问的动态路由表
                    console.log('根据roles权限生成可访问的动态路由表', dynamicRoutes)
                    store.commit('SET_DYNAMIC_ROUTES', dynamicRoutes)

                    // 最终的菜单数据 静态菜单 + 动态菜单组合（侧边栏菜单显示数据源）
                    let finalMenus = []
                    staticRoutes.forEach(staticRoute => {
                        if (!staticRoute.hidden) {
                            // 如果hidden为true 说明不需要在侧边栏展示
                            finalMenus.push(staticRoute)
                        }
                    })
                    let accessNeedShowRoutes = [];
                    for (const obj of accessRoutes) {
                        if (!obj.hidden) {
                            accessNeedShowRoutes.push(obj);
                        }
                    }
                    finalMenus = finalMenus.concat(accessNeedShowRoutes)

                    // 更改菜单数据
                    store.commit('SET_SIDEBAR_ROUTES', finalMenus)
                    console.log('finalMenus', finalMenus)

                    // hack方法 确保addRoutes已完成
                    // next({ ...to })的目的,是保证路由添加完了再进入页面 (可以理解为重进一次)
                    // replace: true, 重进一次, 不保留重复历史
                    // 如果 addRoutes 并未完成，路由守卫会一层一层的执行执行，直到 addRoutes 完成，找到对应的路由
                    next({ ...to, replace: true })
                })
            }).catch(err => {
                console.log('获取用户信息失败 退出登录进入登录页面', err)
                next({ path: '/' })
            })
        } else {
            next()
        }
    } else {
        console.log('未登录')

        if (whiteList.indexOf(to.path) != -1) {
            // 放行
            next()
        } else {
            // 未登录时，注意 如果想未登录也放行 可以特殊处理
            if (to.path !== '/login') {
                // 未登录 但是路由不是进入登录页 则中断 再次进入登录路由
                next({path: '/login'})
                NProgress.done()
            } else {
                // 放行
                next()
            }
        }
    }
});

/**
 * 路由守卫放行后
 */
router.afterEach(() => {
    NProgress.done()
})

export default router;
